package com.rongji.cms.tools.websocket.config; /**
 * @author yang
 * @date 2023/2/6 9:46
 * @description
 */

import com.corundumstudio.socketio.AckMode;
import com.corundumstudio.socketio.SocketConfig;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.annotation.SpringAnnotationScanner;
import com.corundumstudio.socketio.store.RedissonStoreFactory;
import com.corundumstudio.socketio.store.pubsub.PubSubStore;
import com.rongji.cms.tools.common.utils.redis.RedisUtils;
import com.rongji.cms.tools.websocket.config.properties.SocketioProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;

/**
 * @Author: JCccc
 * @Description:
 * @Date: 2022/06/13 21:50
 * 参考：
 * https://blog.csdn.net/qq_35387940/article/details/126058386
 */
@Configuration
@Slf4j
public class SocketIoConfig {

    @Resource
    SocketioProperties socketioProperties;



    @Bean
    public SocketIOServer socketIOServer() {
        SocketConfig socketConfig = new SocketConfig();
        //在默认情况下,当调用close关闭socke的使用,close会立即返回,
        // 但是,如果send buffer中还有数据,系统会试着先把send buffer中的数据发送出去,然后close才返回.
        socketConfig.setTcpNoDelay(true);
        socketConfig.setSoLinger(0);
        socketConfig.setReuseAddress(true);
        com.corundumstudio.socketio.Configuration config = new com.corundumstudio.socketio.Configuration();
        buildSocketConfig(socketConfig, config);
        return new SocketIOServer(config);
    }

    /**
     * 扫描netty-socketIo的注解( @OnConnect、@OnEvent等）
     */
    @Bean
    public SpringAnnotationScanner springAnnotationScanner() {
        return new SpringAnnotationScanner(socketIOServer());
    }

    @Bean
    public PubSubStore pubSubStore(SocketIOServer socketServer) {
        return socketServer.getConfiguration().getStoreFactory().pubSubStore();
    }


    private void buildSocketConfig(SocketConfig socketConfig, com.corundumstudio.socketio.Configuration config) {
        config.setSocketConfig(socketConfig);
        config.setHostname(socketioProperties.getHost());
        config.setPort(socketioProperties.getPort());
        config.setBossThreads(socketioProperties.getBossCount());
        config.setWorkerThreads(socketioProperties.getWorkCount());
        config.setAllowCustomRequests(socketioProperties.isAllowCustomRequests());
        config.setUpgradeTimeout(socketioProperties.getUpgradeTimeout());
        config.setPingTimeout(socketioProperties.getPingTimeout());
        config.setPingInterval(socketioProperties.getPingInterval());
        config.setStoreFactory(createRedissonStoreFactory());
//         FIXME: 2023/2/6 这2个估计跟跨域有关
//        config.setAllowHeaders();
//        config.setOrigin();
        //异常处理
//        config.setExceptionListener(nettyExceptionListener);
        //手动确认
        config.setAckMode(AckMode.MANUAL);
        // 握手协议参数使用JWT的Token认证方案 认证方案
        config.setAuthorizationListener(data -> {
           /* HttpHeaders httpHeaders = data.getHttpHeaders();
            String token = httpHeaders.get("Authorization");*/
                    return  true;
        });

    }


    /**
     * 创建 StoreFactory
     * @return
     */
    private RedissonStoreFactory createRedissonStoreFactory(){
        log.info("创建 RedissonStoreFactory 开始");
        RedissonStoreFactory redissonStoreFactory = new RedissonStoreFactory(RedisUtils.getClient());
        log.info("创建 RedissonStoreFactory 结束");
        return redissonStoreFactory;
    }

}
